package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.commons.constants.CommonConstants;
import com.xuecheng.commons.constants.CourseConstants;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CourseAuditDto;
import com.xuecheng.commons.model.dto.CourseBaseDto;
import com.xuecheng.commons.model.dto.CourseDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.AuthInfoHolder;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.config.MinioProperties;
import com.xuecheng.content.domain.CourseBase;
import com.xuecheng.content.domain.CoursePub;
import com.xuecheng.content.domain.Teachplan;
import com.xuecheng.content.mappers.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.CoursePubService;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.web.exception.BusinessException;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.errors.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itheima
 * @since 2022-07-17
 */
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    MinioClient minioClient;

    @Autowired
    MinioProperties minioProperties;

    @Autowired
    TeachplanService teachplanService;

    @Autowired
    CoursePubService coursePubService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    //分页查询当前机构得课程列表
    @Override
    public ResponseResult courseList(PageRequest request, CourseDto dto) {
        //创建分页参数
        Page<CourseBase> pageParam = new Page<>(request.getPageNo(),request.getPageSize());
        //创建查询条件
        LambdaQueryWrapper<CourseBase> qw = new LambdaQueryWrapper<>();
        String courseName = dto.getCourseName();
        if (!StringUtils.isEmpty(courseName)) {
            qw.like(CourseBase::getName,"%" + courseName + "%");
        }
        String auditStatus = dto.getAuditStatus();
        if (!StringUtils.isEmpty(auditStatus)) {
            qw.eq(CourseBase::getAuditStatus,auditStatus);
        }
        String teachmode = dto.getTeachmode();
        if (!StringUtils.isEmpty(teachmode)) {
            qw.eq(CourseBase::getTeachmode,teachmode);
        }
        //设置机构id
        //qw.eq(CourseBase::getCompanyId, AuthInfoHolder.getCompanyId());  //线程中拿companyId
        //分页查询
        IPage<CourseBase> iPage = this.page(pageParam, qw);  //分页起始条数Page，查询条件QueryWarrper
        //转换PageResponseResult
        return PageResponseResult.okResult(iPage.getTotal(),iPage.getRecords());
    }

    //封面图片的上传
    @Override
    public ResponseResult upload(MultipartFile uploadFile) throws Exception {
        //1.设置上传文件的存储位置和名称
        String filepath = "/images/" + new SimpleDateFormat("yyyy/MM/dd/")
                .format(new Date()) +
                UUID.randomUUID().toString() + uploadFile.getOriginalFilename();
        //2.构造请求参数PutObjectArgs
        PutObjectArgs objectArgs = PutObjectArgs.builder()
                .object(filepath)
                .contentType("/image/jpg")
                .stream(uploadFile.getInputStream(), uploadFile.getInputStream().available(), -1)
                .bucket(minioProperties.getBucket())
                .build();
        //3.发送请求
        minioClient.putObject(objectArgs);
        //4.构造返回
        String urlPath = minioProperties.getDomain() + "/" + minioProperties.getBucket() + filepath;
        return ResponseResult.okResult(urlPath);
    }

    //保存课程
    @Override
    @Transactional
    public ResponseResult saveCourseBase(CourseBaseDto dto) {
        //1.验证数据格式(略)
        //2.将传入的请求参数dto转化为数据库对象courseBase
        CourseBase courseBase = BeanHelper.copyProperties(dto, CourseBase.class);
        //3.设置数据库字段数据
        courseBase.setCompanyName(AuthInfoHolder.getAuthInfo().getCompanyName());
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS); //课程的审核状态
        courseBase.setStatus(CommonConstants.USING_FLAG);      //课程的删除状态
        courseBase.setCreateDate(new Date());  //添加日期
        courseBase.setPlanNum(0);     //默认章节0
        //4.保存
        boolean save = this.save(courseBase);
        if (!save) {
            throw new BusinessException(ErrorCode.ADDEERROR);
        }
        //5.初始化一个课程以及大纲
        Teachplan teachplan = new Teachplan();
        teachplan.setPname(courseBase.getName());
        teachplan.setParentid(0L);
        teachplan.setGrade(CourseConstants.FIRST_LEVEL);
        teachplan.setCourseId(courseBase.getId());  //当前课程计划所属的课程id
        teachplan.setStatus(CommonConstants.USING_FLAG);
        teachplan.setCreateDate(new Date());
        teachplanService.save(teachplan);

        //6.构造返回
        Map map = new HashMap();
        map.put("courseBaseId",courseBase.getId());
        return ResponseResult.okResult(map);
    }

    //修改课程
    @Override
    public ResponseResult updateCourseBase(CourseBaseDto dto) {
        //1.验证数据格式(略)
        //2.根据id查询课程数据
        CourseBase courseBase = this.getById(dto.getId());
        if (courseBase == null) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        //3.判断课程状态，是否可以修改课程
        String auditStatus = courseBase.getAuditStatus();
        if (!CourseConstants.AUDIT_DISPAST_STATUS.equals(auditStatus) &&
                !CourseConstants.AUDIT_UNPAST_STATUS.equals(auditStatus)) {
            throw new BusinessException(ErrorCode.UPDATEEERROR);
        }
        //4.修改课程
        CourseBase course = BeanHelper.copyProperties(dto, CourseBase.class);  //转化为java实体类
        boolean update = this.updateById(course);
        if (!update) {
            throw new BusinessException(ErrorCode.ADDEERROR);
        }
        //5.返回值
        Map map = new HashMap();
        map.put("courseBaseId",dto.getId());
        return ResponseResult.okResult(map);
    }

    //删除课程
    @Override
    public ResponseResult deleteCourseBase(Long courseId) {
        CourseBase courseBase = this.getById(courseId);
        if (courseBase == null) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        String auditStatus = courseBase.getAuditStatus();
        if (!CourseConstants.AUDIT_UNPAST_STATUS.equals(auditStatus) &&
                !CourseConstants.AUDIT_UNLINE_STATUS.equals(auditStatus)) {
            throw new BusinessException(ErrorCode.DELETEERROR);
        }
        boolean remove = this.removeById(courseId);
        if (!remove) {
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        return ResponseResult.okResult();
    }

    //课程提交
    @Override
    public ResponseResult commit(Long courseBaseId) {
        //1.根据id查询课程
        CourseBase courseBase = this.getById(courseBaseId);
        if (courseBase == null) {
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        //2.设置状态
        courseBase.setAuditStatus(CourseConstants.AUDIT_COMMIT_STATUS);
        //3.更新数据库
        boolean update = this.updateById(courseBase);
        if (!update) {
            throw new BusinessException(ErrorCode.ADDEERROR);
        }
        return ResponseResult.okResult();
    }

    //管理员审核课程
    @Override
    public ResponseResult approve(CourseAuditDto dto) {
        //1.根据id查询课程
        CourseBase courseBase = this.getById(dto.getCourseBaseId());
        if (courseBase == null) {
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        //2.设置状态和审核意见
        courseBase.setAuditStatus(dto.getAuditStatus());
        courseBase.setAuditMind(dto.getAuditMind());
        boolean update = this.updateById(courseBase);
        if (!update) {
            throw new BusinessException(ErrorCode.UPDATEEERROR);
        }
        return ResponseResult.okResult();
    }

    //已发布课程下架
    @Override
    public ResponseResult offline (Long courseId) throws Exception {
        //下架课程计划
        CourseBase courseBase = this.getById(courseId);
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS);
        this.updateById(courseBase);
        //删除课程发布
        LambdaQueryWrapper<CoursePub> qw = new LambdaQueryWrapper<>();
        qw.eq(CoursePub::getCourseId,courseId);
        CoursePub coursePub = coursePubService.getOne(qw);
        Long coursePubId = coursePub.getId();
        boolean remove = coursePubService.removeById(coursePubId);
        if (!remove) {
             throw new BusinessException(ErrorCode.DELETEERROR);
        }
        //删除minio文件
        String filePath = "/pages/" + coursePubId + ".html";
        RemoveObjectArgs build = RemoveObjectArgs.builder()
                .object(filePath)
                .bucket(minioProperties.getBucket())
                .build();
        minioClient.removeObject(build);
        //发送mq消息，删除es索引
        rabbitTemplate.convertAndSend("content-exchange-two","course.delete",coursePubId);
        return ResponseResult.okResult();
    }
}
